package com.sghd.charge.module.payment.iospay;

import com.sghd.charge.module.model.ChannelType;
import com.sghd.charge.module.order.entity.Goods;
import com.sghd.charge.module.order.entity.Order;
import com.sghd.charge.module.payment.AbstractProcessor;
import com.sghd.charge.module.payment.ChargeService;
import com.sghd.charge.module.payment.iospay.model.Receipt;
import com.sghd.charge.module.payment.iospay.model.ReceiptRsp;
import com.sghd.charge.module.payment.iospay.model.VerifyInfo;
import com.sghd.common.utils.codec.CryptUtils;
import com.sghd.common.utils.json.JsonUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import javax.servlet.ServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Optional;

import static com.sghd.charge.module.model.ChargeConstant.IOSPAY_SANBOX;

/**
 * @author frank
 * @date 2019-03-06 14:01
 * @desc
 **/
@Component
public class IosProcessor extends AbstractProcessor {

    /** 生产环境验证地址*/
    private static final String VERIFYRECEIPT = "https://buy.itunes.apple.com/verifyReceipt";
    /** 沙盒环境验证地址*/
    private static final String SANDBOX_VERIFYRECEIPT = "https://sandbox.itunes.apple.com/verifyReceipt";
    private static final String RECEIPT_DATA = "receipt-data";
    private static final String ORDER_ID = "orderId";
    private static final String PLAYER_ID = "playerId";

    @Autowired
    @Qualifier("httpsTemplate")
    private RestTemplate restTemplate;

    /** 是否是沙盒环境*/
    @Value(IOSPAY_SANBOX)
    private boolean isSanbox;
    @Autowired
    private ChargeService chargeService;

    @Override
    public String getAddtion(Goods goods, long orderId, String ip) throws Exception {
        return null;
    }

    @Override
    public ChannelType getType() {
        return ChannelType.IOS;
    }

    @Override
    public String notify(ServletRequest request) {
        Map<String, String> params = getRequest(request);
        String receipt = params.get(RECEIPT_DATA);
        Long orderId = MapUtils.getLong(params, ORDER_ID);
        Long playerId = MapUtils.getLong(params, PLAYER_ID);

        if (orderId == null) {
            return "fail: orderId is null";
        }
        Optional<Order> orderOptional = orderRepository.findById(orderId);
        if (!orderOptional.isPresent()) {
            return "fail: order not found";
        }
        VerifyInfo verify = verifyReceipt(receipt.trim());
        Order order = orderOptional.get();
        //验证失败
        if (verify.fail()) {
            order.setAttachment(verify.getMsg());
            orderRepository.save(order);
            return "fail:" + verify.getMsg();
        }
        //验证成功
        Map<String, Object> attachment = new HashMap<>(2);
        //交易流水号
        attachment.put(ChargeService.TRANSACTION_NUMBER, verify.getTransactionId());
        int totalFee = verify.getTotalFee();
        if (isSanbox) {
            //沙盒环境不验证，支付金额
            totalFee = order.getMoney();
        }
        attachment.put(ChargeService.TOTAL_FEE, totalFee);
        attachment.put(ChargeService.CHANNEL_TYPE, getType().toString());
        chargeService.charge(orderId, attachment);
        return "success";
    }

    /**
     *
     * @param receiptData 支付凭证
     * @return
     * @throws IOException
     */
    public VerifyInfo verifyReceipt(String receiptData) {
        //Base64编码
        receiptData = CryptUtils.base64Encode(receiptData);
        Map<String, String> verifyData = new HashMap<>(1);
        verifyData.put(RECEIPT_DATA, receiptData);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        HttpEntity<String> entity = new HttpEntity<>(JsonUtils.object2String(verifyData), headers);
        String url = VERIFYRECEIPT;
        if (isSanbox) {
            url = SANDBOX_VERIFYRECEIPT;
        }
        ReceiptRsp receiptRsp = null;
        try {
            receiptRsp = restTemplate.postForObject(url, entity, ReceiptRsp.class);
        } catch (Exception e) {
            //向苹果验证支付凭证发生错误
            return VerifyInfo.ERROR(-1, e.getMessage());
        }
        if (receiptRsp.getStatus() != 0) {
            return VerifyInfo.ERROR(-1, "ios status: " + receiptRsp.getStatus());
        }
        Receipt receipt = receiptRsp.getReceipt();
        if (receipt == null) {
            return VerifyInfo.ERROR(-1, "ios receipt null :");
        }
        //没有商品信息(有可能是使用低版本的ios固件支付 参数不一致，检查in_app参数中是否携带商品信息)
        if (StringUtils.isBlank(receipt.getProductId()) || StringUtils.isBlank(receipt.getQuantity())) {
            return VerifyInfo.ERROR(-1, "not found productId and quantity => " + JsonUtils.object2String(receipt.getInApp()));
        }
        try {
            return VerifyInfo.SUCCESS(receipt.getProductId(), receipt.getQuantity(), receipt.getTransactionId());
        } catch (Exception e) {
            return VerifyInfo.ERROR(-1, "产品PRODUCT_ID格式[" + receipt.getProductId() + "]不正确！解析价格异常！");
        }
    }


    private Map<String, String> getRequest(ServletRequest request) {
        try {
            Map<String, String> params = new HashMap<>();
            Map requestParams = request.getParameterMap();
            for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
                String name = (String) iter.next();
                String[] values = (String[]) requestParams.get(name);
                String valueStr = "";
                for (int i = 0; i < values.length; i++) {
                    valueStr = (i == values.length - 1) ? valueStr + values[i]
                            : valueStr + values[i] + ",";
                }
                params.put(name, valueStr);
            }
            logger.info("收到支付凭证：{}", JsonUtils.object2String(params));
            return params;
        } catch (Exception e) {
            logger.error("获取支付凭证发生错误！");
        }
        return null;
    }
}
